package com.anlw.data;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.Table;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.anlw.common.utils.GenericsUtils;


/*
 * 
 * @author jinn
 * @version 1.0 2010-4-12
 * @description  JPA 数据操作实现
 */

@Transactional
@Component
public abstract class JPABaseDAOImpl<T> implements IBaseDAO<T>  {

	private static Logger logger = Logger.getLogger(JPABaseDAOImpl.class);
	private Class<T> entityClass = GenericsUtils.getSuperClassGenricType(this.getClass());
	public String entityName = getEntityName(this.entityClass);//这个对象可以在子类中使用
	
	@PersistenceContext
	protected EntityManager em;
	
	/**
	 * 创建jdbcsql 更新
	 * 
	 * @param sql
	 * @return
	 */
	@Override
	public Integer jdbcExecUpdate(String sql) {
		try {
			Query query = null;
			if (StringUtils.isNotEmpty(sql)) {
				query = em.createNativeQuery(sql);
				int result = query.executeUpdate();
				return result;
			}

		} catch (Exception ex) {
			logger.error(ex.getMessage());
			ex.printStackTrace();
		}
		return 0;
	}

	/**
	 * 创建jdbc对象查询
	 * 
	 * @param sql
	 * @param cls
	 *            返回类型对象
	 * @return
	 */
	@Override
	public List<Object[]> jdbcExecQuery(String sql, Class cls) {
		try {
			Query query = null;
			if (StringUtils.isNotEmpty(sql)) {
				if (cls == null) {
					query = em.createNativeQuery(sql);
				} else {
					query = em.createNativeQuery(sql, cls);
				}
				List relist = query.getResultList();
				return relist;
			}
		} catch (Exception ex) {
			logger.error(ex.getMessage());
			ex.printStackTrace();
		}
		return null;
	}

	
	/*
	 * @description 批量保存
	 * 
	 * @params entity 泛型实体类
	 * 
	 * @params object 另外的参数
	 */
	@Override
	public void jdbcSaveEntityBatch(List<T> listEntity) {
		Map tabinfoMap = getTableInfo(entityClass);
		List colmunlist = (List) tabinfoMap.get("tablecolumn");
		List filedslist = (List) tabinfoMap.get("classfileds");

		StringBuilder sb = new StringBuilder();
		sb.append("insert into ");
		sb.append(tabinfoMap.get("tablename"));
		sb.append(" (");
		sb.append(StringUtils.join(colmunlist, ","));
		sb.append(" ) values ");
		try {
			for (int in = 0; in < listEntity.size(); in++) {
				Object entity = listEntity.get(in);

				sb.append("(");
				for (int i = 0; i < filedslist.size(); i++) {
					sb.append("'");
					String filed = (String) filedslist.get(i);
					String value;

					value = BeanUtils.getProperty(entity, filed);

					value = StringUtils.defaultIfEmpty(value, "");
					sb.append(value);
					sb.append("'");
					if (i < (filedslist.size() - 1)) {
						sb.append(",");
					}

				}
				sb.append(")");
				if (in < (listEntity.size() - 1)) {
					sb.append(",");
				}

			}
		} catch (Exception ex) {
			logger.error(ex.getMessage());
			ex.printStackTrace();
		}

		jdbcExecUpdate(sb.toString());

	}
	/*
	 * @description 保存
	 * 
	 * @params entity 泛型实体类
	 * 
	 * @params object 另外的参数
	 */
	@Override
	@Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public void execSave(T entity) {
		try{
			em.persist(entity);		
		}catch (Exception ex) {
			logger.error(ex.getMessage());
			ex.printStackTrace();
		}
	
	}
	/**
	 * @description 批量保存实例
	 * @param listEntity
	 */
	@Override
	@Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public void execSaveBatch(List<T> listEntity) {
		try {
			for (int i = 0; i < listEntity.size(); i++) {

				em.persist(listEntity.get(i));
				if (i % 50 == 0) {
					em.flush();
					em.clear();
				}
			}
			em.flush();
			em.clear();
		} catch (Exception ex) {
			logger.error(ex.getMessage());
			ex.printStackTrace();
		}

	}

	/**
	 * 查询jpql语言
	 * 
	 * @param jpql
	 * @param classname
	 * @return
	 */

	@Override
	public Object queryUpdate(String jpql) {
		Query query = null;
		try {
			if (StringUtils.isEmpty(jpql)) {
				return null;
			}

			query = em.createQuery(jpql);

			return query.executeUpdate();

		} catch (Exception ex) {
			logger.error(ex.getMessage());
			ex.printStackTrace();
		}
		return null;
	}
	/*
	 * @description 更新
	 * 
	 * @params entity 泛型实体类
	 * 
	 * @params object 另外的参数
	 */
	@Override
	public void execUpdate(T entity) {
		try {
			em.merge(entity);
		} catch (Exception ex) {
			logger.error(ex.getMessage());
			ex.printStackTrace();
		}
	}

	/*
	 * @description 根据ID查找
	 * 
	 * @params entityid 实体类Id
	 */
	@Override
	public T execFindById(Serializable entityid) {
		try {
			return em.find(entityClass, entityid);
		} catch (Exception ex) {
			logger.error(ex.getMessage());
			ex.printStackTrace();
		}
		return null;
	}
	/*
	 * @description count计数
	 * 
	 * @params whereJPQL 查询语句 如：name=1? and pwd=2?
	 * 
	 * @params params 查询参数值
	 */
	@Override
	public Long queryCount(String whereJPQL, Map params) {
		try {
			String entityName = getEntityName(this.entityClass);
			String where = (whereJPQL != null && !"".equals(whereJPQL.trim())) ? " where " + whereJPQL : "";
			Query query = em.createQuery("select count(o) from " + entityName + " o " + where);
			setQueryParamer(query, params);
			Long count = (Long) query.getSingleResult();
			return count;
		} catch (Exception ex) {
			logger.error(ex.getMessage());
			ex.printStackTrace();
		}
		return null;
	}

	/*
	 * @description 根据ID删除
	 * 
	 * @params ids 实体类Id
	 */
	@Override
	public void execDelete(Object[] ids) {
		try {
			for (Object id : ids) {
				if (id != null) {
					em.remove(em.getReference(this.entityClass, id));
				}
			}
		} catch (Exception ex) {
			logger.error(ex.getMessage());
			ex.printStackTrace();
		}

	}

	/*
	 * @description 根据条件删除
	 * 
	 * @params ids 实体类Id
	 */
	@Override
	public void queryDeleteBatch(String whereJPQL) {
		try {
			if (StringUtils.isNotEmpty(whereJPQL)) {
				
				String where = (whereJPQL != null && !"".equals(whereJPQL.trim())) ? " where " + whereJPQL : "";
				Query query = em.createQuery("delete from " + entityName + " o " + where);
				query.executeUpdate();
			}

		} catch (Exception ex) {
			logger.error(ex.getMessage());
			ex.printStackTrace();
		}

	}

	/**
	 * 创建本有命名的jsql查询
	 * 
	 * @param sql
	 * @param classname
	 * @return
	 */
	@Override
	public int createNamedUpdate(String namedSql, Class<T> classname) {
		Query qr=null;
		try {
			
			if (StringUtils.isEmpty(namedSql)) {
				return -1;
			}
			if (classname == null) {
				qr= em.createNamedQuery(namedSql);
			} else {
				qr=em.createNamedQuery(namedSql, classname);
			}
			return qr.executeUpdate();
		} catch (Exception ex) {
			logger.error(ex.getMessage());
			ex.printStackTrace();
		}
		return -1;
	}
	/**
	 * 创建本有命名的jsql查询
	 * 
	 * @param sql
	 * @param classname
	 * @return
	 */
	@Override
	public List createNamedList(String namedSql, Class<T> classname) {
		Query qr=null;
		try {
			
			if (StringUtils.isEmpty(namedSql)) {
				return null;
			}
			if (classname == null) {
				qr= em.createNamedQuery(namedSql);
			} else {
				qr=em.createNamedQuery(namedSql, classname);
			}
			return qr.getResultList();
		} catch (Exception ex) {
			logger.error(ex.getMessage());
			ex.printStackTrace();
		}
		return null;
	}
	/**
	 * 创建本有命名的jsql查询
	 * 
	 * @param sql
	 * @param classname
	 * @return
	 */
	@Override
	public Object createNamedObject(String namedSql, Class<T> classname) {
		Query qr=null;
		try {
			
			if (StringUtils.isEmpty(namedSql)) {
				return null;
			}
			if (classname == null) {
				qr= em.createNamedQuery(namedSql);
			} else {
				qr=em.createNamedQuery(namedSql, classname);
			}
			return qr.getSingleResult();
		} catch (Exception ex) {
			logger.error(ex.getMessage());
			ex.printStackTrace();
		}
		return null;
	}

	/**
	 * 查询jpql语言
	 * 
	 * @param jpql
	 * @param classname
	 * @return
	 */
	@Override
	public List queryForList(String jpql, Class<T> classname) {
		Query query = null;
		try {
			if (StringUtils.isEmpty(jpql)) {
				return null;
			}
			if (classname == null) {
				query = em.createQuery(jpql);
			} else {
				query = em.createQuery(jpql, classname);
			}
			return query.getResultList();

		} catch (Exception ex) {
			logger.error(ex.getMessage());
			ex.printStackTrace();
		}
		return null;
	}

	/**
	 * 查询jpql语言
	 * 
	 * @param jpql
	 * @param classname
	 * @return
	 */

	@Override
	public Object queryForObject(String jpql, Class<T> classname) {
		Query query = null;
		try {
			if (StringUtils.isEmpty(jpql)) {
				return null;
			}
			if (classname == null) {
				query = em.createQuery(jpql);
			} else {
				query = em.createQuery(jpql, classname);
			}
			return query.getSingleResult();

		} catch (Exception ex) {
			logger.error(ex.getMessage());
			ex.printStackTrace();
		}
		return null;
	}

	

	/*
	 * @description 分页查询
	 * 
	 * @params startIndex 页码
	 * 
	 * @params maxResult 最大的返回记录数
	 * 
	 * @params whereJPQL 查询语句 如：name=1? and pwd=2?
	 * 
	 * @params params 查询参数值
	 * 
	 * @params orderby 排序条件 如 ：key=name value=desc .....
	 */
	@Override
	public QueryResult queryData(int startIndex, int maxResult, String whereJPQL, Map params,
			LinkedHashMap<String, String> orderby) {
		try {
			QueryResult qr = new QueryResult();
			String entityName = getEntityName(this.entityClass);
			String where = (whereJPQL != null && !"".equals(whereJPQL.trim())) ? " where " + whereJPQL : "";
			String jpql = "select o from " + entityName + " o " + where + buildOrderBy(orderby);
			System.out.println("jpql==="+jpql);
			Query query = em.createQuery(jpql);
			setQueryParamer(query, params);
			if (startIndex != -1 && maxResult != -1) {
				query.setFirstResult(startIndex).setMaxResults(maxResult);
			}
			List resultList = query.getResultList();
			qr.setResultList(resultList);
			query = em.createQuery("select count(o) from " + entityName + " o " + where);
			setQueryParamer(query, params);
			qr.setTotalResult((Long) query.getSingleResult());
			return qr;
		} catch (Exception ex) {
			logger.error(ex.getMessage());
			ex.printStackTrace();
		}
		return null;
	}

	
	/*
	 * @description 分页查询
	 * 
	 * @params startIndex 页码
	 * 
	 * @params maxResult 最大的返回记录数
	 */
	@Override
	public QueryResult queryData(int startIndex, int maxResult) {
		String whereJPQL = null;
		Map params = null;
		LinkedHashMap<String, String> orderby = null;
		return queryData(startIndex, maxResult, whereJPQL, params, orderby);
	}

	/*
	 * @description 分页查询
	 * 
	 * @params startIndex 页码
	 * 
	 * @params maxResult 最大的返回记录数
	 * 
	 * @params whereJPQL 查询语句 如：name=1? and pwd=2?
	 * 
	 * @params params 查询参数值
	 */
	@Override
	public QueryResult queryData(int startIndex, int maxResult, String whereJPQL, Map params) {
		return queryData(startIndex, maxResult, whereJPQL, params, null);
	}

	/*
	 * @description 分页查询
	 * 
	 * @params startIndex 页码
	 * 
	 * @params maxResult 最大的返回记录数
	 * 
	 * @params orderby 排序条件 如 ：key=name value=desc .....
	 */
	@Override
	public QueryResult queryData(int startIndex, int maxResult, LinkedHashMap<String, String> orderby) {
		String whereJPQL = null;
		Map params = null;
		return queryData(startIndex, maxResult, whereJPQL, params, orderby);
	}

	/*
	 * @description 条件排序查询
	 * 
	 * @params startIndex 页码
	 * 
	 * @params maxResult 最大的返回记录数
	 * 
	 * @params whereJPQL 查询语句 如：name=1? and pwd=2?
	 * 
	 * @params params 查询参数值
	 * 
	 * @params orderby 排序条件 如 ：key=name value=desc .....
	 */
	@Override
	public QueryResult queryData(String whereJPQL, Map params, LinkedHashMap<String, String> orderby) {
		return queryData(-1, -1, whereJPQL, params, orderby);
	}

	/*
	 * @description 条件查询
	 * 
	 * @params whereJPQL 查询语句 如：name=1? and pwd=2?
	 * 
	 * @params params 查询参数值
	 */
	@Override
	public QueryResult queryData(String whereJPQL, Map params) {
		return queryData(-1, -1, whereJPQL, params, null);
	}

	/*
	 * @description order by查询
	 * 
	 * @params orderby 排序条件 如 ：key=name value=desc .....
	 */
	@Override
	public QueryResult queryData(LinkedHashMap<String, String> orderby) {
		String whereJPQL = null;
		Map params = null;
		return queryData(-1, -1, whereJPQL, params, orderby);
	}

	/*
	 * @description 装载查询参数
	 * 
	 * @params query 查询
	 * 
	 * @params params 查询参数
	 */

	private static void setQueryParamer(Query query, Map params) {
		if (params != null) {
			for (Object key : params.keySet()) {
				query.setParameter(key.toString(), params.get(key));
			}
		}

	}

	/*
	 * @description 连接排序参数
	 * 
	 * @params orderby 排序参数
	 */
	private static String buildOrderBy(LinkedHashMap<String, String> orderby) {
		StringBuilder sb = new StringBuilder();

		if (orderby != null && orderby.size() > 0) {
			sb.append(" order by ");
			for (String key : orderby.keySet()) {
				sb.append("o.").append(key).append(" ").append(orderby.get(key)).append(",");

			}
			sb.deleteCharAt(sb.length() - 1);
		}

		return sb.toString();
	}

	/*
	 * @description 查找实体类
	 * 
	 * @params entityClass class
	 */
	private static <E> String getEntityName(Class<E> entityClass) {
		String entityname = entityClass.getSimpleName();
		Entity entity = entityClass.getAnnotation(Entity.class);

		if ((entity.name() != null) && (!"".equals(entity.name())))
			entityname = entity.name();

		return entityname;
	}

	private static boolean isBasicType(Class<?> Type){
		
		if(Type.isPrimitive()){
			// boolean、byte、char、short、int、long、float 和 double。
			return true;
		}else if(Type.equals(Boolean.TYPE)){
			return true;
		}else if(Type.equals(Byte.TYPE)){
			return true;			
		}else if(Type.equals(Character.TYPE)){
			return true;
		}else if(Type.equals(Short.TYPE)){
			return true;
		}else if(Type.equals(Integer.TYPE)){
			return true;
		}else if(Type.equals(Long.TYPE)){
			return true;
		}else if(Type.equals(Float.TYPE)){
			return true;
		}else if(Type.equals(Long.TYPE)){
			return true;
		}else if(Type.equals(Double.TYPE)){
			return true;
		}else if(Type.equals(String.class)){
			return true;
		}else{
			return false;
		}
		
	}
	/*
	 * @description 根据实体类取表格信息
	 * 
	 * @params entityClass class
	 */
	private static <E> Map getTableInfo(Class<E> entityClass) {
		String entityname = entityClass.getSimpleName();
		Table entity = entityClass.getAnnotation(Table.class);

		if ((entity.name() != null) && (!"".equals(entity.name())))
			entityname = entity.name();

		Map map = new HashMap();
		map.put("tablename", entityname);

		
		boolean methodcolum=false;
		List tableColmun = new ArrayList();
		List classFileds = new ArrayList();
		// 反射方法
		Method[] methods = entityClass.getMethods();
		Map methodMap = new HashMap();
		for (Method metd : methods) {
			methodMap.put(metd.getName().toUpperCase(), metd);
			if(isBasicType(metd.getReturnType())){
				GeneratedValue generatedvalue = metd.getAnnotation(GeneratedValue.class);
				Column column = metd.getAnnotation(Column.class);
				if (generatedvalue == null) {
					if ((column != null) && (!"".equals(column.name()))) {
						tableColmun.add(column.name());
						methodcolum=true;
					} 
				}
				
			}			
		}
		// 反射字段
		Field[] fields = entityClass.getDeclaredFields();
		for (Field field : fields) {
			String methodstring = ("get" + field.getName()).toUpperCase();
			if((methodMap.containsKey(methodstring))&&(isBasicType(field.getType()))) {
				Column column = field.getAnnotation(Column.class);
				GeneratedValue generatedvalue = field.getAnnotation(GeneratedValue.class);
				if (generatedvalue == null) {
					if(!methodcolum){
					if ((column != null) && (!"".equals(column.name()))) {
						tableColmun.add(column.name());
					} else {
						tableColmun.add(field.getName());
					}
					}else{
						
						classFileds.add(field.getName());
					}
				}
				
			}
		}
		Collections.sort(tableColmun);
		Collections.sort(classFileds);
		map.put("tablecolumn", tableColmun);
		map.put("classfileds", classFileds);

		return map;
	}

}
